﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 递归解释器
{
    public sealed class LowSet : Dictionary<TokenEnum, int>
    {
        public int Low { get; } = -1;
        public int Height { get; } = 2;
        public static LowSet Instance
        {
            get => inner.val;
        }
        private class inner
        {
            private inner()
            {

            }
            internal static readonly LowSet val = new LowSet();
        }
        static LowSet()
        {

        }

        private LowSet()
        {
            Add(TokenEnum.plus, 1);
            Add(TokenEnum.minus, 1);
            Add(TokenEnum.slash, 2);
            Add(TokenEnum.asterisk, 2);
            Add(TokenEnum.assigh, 0);
            Add(TokenEnum.none, -1);
        }

        public int GetLowSet(TokenEnum token)
        {
            int lowset = 0;
            if (this.ContainsKey(token))
            {
                lowset = this[token];

            }
            return lowset;
        }
    }
    public enum TokenEnum
    {
        none,
        eof,
        value,
        lp,
        rp,
        /// <summary>
        /// -
        /// </summary>
        minus,
        /// <summary>
        /// +
        /// </summary>
        plus,
        /// <summary>
        /// =
        /// </summary>
        assigh,
        /// <summary>
        /// *
        /// </summary>
        asterisk,
        /// <summary>
        /// /
        /// </summary>
        slash
    }
    public class Token
    {
        public Token()
        {

        }
        public Token(TokenEnum tokenType, string value)
        {
            TokenType = tokenType;
            Value = value;
        }
        public Token(TokenEnum tokenType, char value)
        {
            TokenType = tokenType;
            Value = value.ToString();
        }
        public TokenEnum TokenType { get; set; }
        public string Value { get; set; }
    }
    public class Lexer
    {
        /// <summary>
        /// 创建一个新的lexer
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static Lexer Create(string input)
        {
            var lexer = new Lexer(input);
            lexer.ReadChar();
            return lexer;
        }
        /// <summary>
        /// 不可实例化
        /// </summary>
        static Lexer()
        {

        }
        /// <summary>
        /// 保持权限等级,实例化
        /// </summary>
        /// <param name="input"></param>
        private Lexer(string input)
        {
            Input = input;
        }
        /// <summary>
        /// 读取下一个
        /// </summary>
        public void ReadChar()
        {
            if (ReadPosition >= Input.Length)
            {
                CharValue = (char)0;
            }
            else
            {
                CharValue = Input[ReadPosition];
            }
            //交换位置
            Position = ReadPosition;
            //指向下一个
            ReadPosition += 1;
        }
        /// <summary>
        /// 获取下一个token
        /// </summary>
        /// <returns><seealso cref="Token"/></returns>
        public Token NextToken()
        {
            Token token = null;
            //跳过空白字符
            SkipWhitespace();
            //筛选当前字符
            switch (CharValue)
            {
                case '=':
                    token = new Token(TokenEnum.asterisk, CharValue);
                    break;

                case '(':
                    token = new Token(TokenEnum.lp, CharValue);
                    break;
                case ')':
                    token = new Token(TokenEnum.rp, CharValue);
                    break;
                case '+':
                    token = new Token(TokenEnum.plus, CharValue);
                    break;
                case '-':
                    token = new Token(TokenEnum.minus, CharValue);
                    break;
                case '*':
                    token = new Token(TokenEnum.asterisk, CharValue);
                    break;
                case '/':
                    token = new Token(TokenEnum.slash, CharValue);
                    break;
                default:
                    token = new Token();
                    if (IsDigit(CharValue))
                    {
                        token.Value = ReadNumber();
                        token.TokenType = TokenEnum.value;
                        return token;
                    }
                    else
                    {
                        token.Value = null;
                        token.TokenType = TokenEnum.eof;
                        return token;
                    }

            }
            ReadChar();
            return token;
        }
        public string ReadString()
        {
            int count = 0;
            var pos = Position + 1;
            while (true)
            {
                ReadChar();
                count++;
                if (Input[this.Position] == '"' || Input[this.Position] == char.MinValue)
                {
                    count--;
                    break;
                }

            }
            return Input.Substring(pos, count);
        }
        /// <summary>
        /// 读取id
        /// </summary>
        /// <returns></returns>
        public string ReadIdentifier()
        {
            var position = Position;
            int count = 0;
            while (IsLetter(CharValue))
            {
                ReadChar();
                count++;
            }
            return Input.Substring(position, count);
        }
        /// <summary>
        /// 是否为字符
        /// </summary>
        /// <param name="ch"></param>
        /// <returns></returns>
        public bool IsLetter(char ch)
        {
            var x = 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_';
            return x;
        }
        /// <summary>
        /// 跳过空白
        /// </summary>
        public void SkipWhitespace()
        {
            while (Char.IsWhiteSpace(CharValue) || CharValue == '\t' || CharValue == '\n' || CharValue == '\r')
            {
                ReadChar();
            }
        }

        /// <summary>
        /// 读取浮点数
        /// </summary>
        /// <returns></returns>
        public string ReadNumber()
        {
            var position = Position;
            int count = 0;
            while (IsDigit(CharValue))
            {
                ReadChar();
                count++;
            }
            if (CharValue == '.')
            {
                ReadChar();
                count++;
            }
            while (IsDigit(CharValue))
            {
                ReadChar();
                count++;
            }
            return Input.Substring(position, count);
        }
        /// <summary>
        /// 是否为字符
        /// </summary>
        /// <param name="ch">参数</param>
        /// <returns></returns>
        public bool IsDigit(char ch)
        {
            //  char.IsDigit(ch);
            return '0' <= ch && ch <= '9';
        }
        /// <summary>
        /// 向前看一个字符
        /// </summary>
        /// <returns></returns>
        public char PeekChar()
        {
            if (ReadPosition >= Input.Length)
                return (char)0;
            else
                return Input[ReadPosition];
        }
        /// <summary>
        /// 输入的字符
        /// </summary>
        public string Input { get; set; }
        /// <summary>
        /// 当前字符位置
        /// </summary>
        public int Position { get; set; }
        /// <summary>
        /// 下一个字符位置
        /// </summary>
        public int ReadPosition { get; set; }
        /// <summary>
        /// 当前char
        /// </summary>
        public char CharValue { get; set; }

    }
    public class Expression
    {
        //public Expression Left { get; set; }
        //public string Operator { get; set; }
        //public Expression Right { get; set; }
        public Token Token { get; set; }
    }
    public class DoubleExpression : Expression
    {
        public double Value { get; set; }
    }
    public class PrefixExpression : Expression
    {
        public string Operator { get; set; }
        public Expression Right { get; set; }
    }
    public class InfixExpression : Expression
    {
        public Expression Left { get; set; }
        public string Operator { get; set; }
        public Expression Right { get; set; }
    }
    public class Statement
    {

    }
    public class ExpressionStatement : Statement
    {
        public Expression Expression { get; set; }
    }
    public class BlockStatement : Statement
    {
        public List<Statement> ExpressionList { get; set; } = new List<Statement>();
    }
    public class Parser
    {
        public Token CurToken { get; set; }
        public Token PeekToken { get; set; }
        public static Parser Instance
        {
            get => Inner.parser;
        }
        private class Inner
        {
            private Inner()
            {

            }
            internal readonly static Parser parser = new Parser();
        }
        static Parser()
        {

        }
        private Parser()
        {

        }
        public Lexer Lexer { get; set; }
        public BlockStatement Start(Lexer lexer)
        {

            BlockStatement blockStatement = new BlockStatement();
            Lexer = lexer;
            SetPreFix(TokenEnum.value, ValueExpression);
            SetPreFix(TokenEnum.minus, _PrefixExpression);
            SetPreFix(TokenEnum.lp, GroupExpression);
            SetInFix(TokenEnum.minus, _InfixExpression);
            SetInFix(TokenEnum.plus, _InfixExpression);
            SetInFix(TokenEnum.slash, _InfixExpression);
            SetInFix(TokenEnum.asterisk, _InfixExpression);
            NextToken();
            NextToken();
            while (!CurTokenIs(TokenEnum.eof))
            {
                var stmt = ParserStatement();
                if (stmt != null)
                {
                    blockStatement.ExpressionList.Add(stmt);
                }
                NextToken();
            }
            return blockStatement;
        }
        public void NextToken()
        {
            CurToken = PeekToken;
            PeekToken = Lexer.NextToken();
        }
        public Expression ValueExpression()
        {
            DoubleExpression exp = new DoubleExpression();
            double v;
            if (double.TryParse(CurToken.Value, out v))
            {
                exp.Token = CurToken;
                exp.Value = v;
                return exp;
            }
            else
            {
                throw new NotImplementedException();
            }
        }
        public Expression _PrefixExpression()
        {
            PrefixExpression exp = new PrefixExpression();
            exp.Token = CurToken;
            exp.Operator = CurToken.Value;
            NextToken();
            exp.Right = ParserExpression(LowSet.Instance.Height);
            return exp;
        }
        public Expression GroupExpression()
        {
            NextToken();
            var exp = ParserExpression();
            if (!ExpectPeek(TokenEnum.rp))
            {
                return null;
            }
            return exp;
        }
        public Expression _InfixExpression(Expression Left)
        {
            InfixExpression exp = new InfixExpression();
            exp.Token = CurToken;
            exp.Operator = CurToken.Value;
            exp.Left = Left;
            int lowset = 0;
            if (LowSet.Instance.ContainsKey(CurToken.TokenType))
            {
                lowset = LowSet.Instance[CurToken.TokenType];
            }
            NextToken();
            exp.Right = ParserExpression(lowset);
            return exp;
        }
        public Expression ParserExpression(int lowset = 0)
        {
            var prefix = Prefix[CurToken.TokenType];
            if (prefix == null)
            {
                return null;
            }
            Expression exp = null;
            exp = prefix();
            while (!PeekTokenIs(TokenEnum.eof) && lowset < LowSet.Instance.GetLowSet(PeekToken.TokenType))
            {
                var infix = Infix[PeekToken.TokenType];
                if (infix == null)
                {
                    return exp;
                }
                NextToken();
                exp = infix(exp);
            }
            return exp;
        }
        public Statement ParserStatement()
        {
            ExpressionStatement exp = new ExpressionStatement();
            exp.Expression = ParserExpression(LowSet.Instance.Low);
            if (!PeekTokenIs(TokenEnum.eof))
            {
                NextToken();
            }
            return exp;
        }
        public void SetPreFix(TokenEnum token, Func<Expression> func)
        {
            Prefix.Add(token, func);
        }
        public void SetInFix(TokenEnum token, Func<Expression, Expression> func)
        {
            Infix.Add(token, func);
        }
        public bool PeekTokenIs(TokenEnum token)
        {
            return PeekToken.TokenType == token;
        }
        public bool CurTokenIs(TokenEnum token)
        {
            return CurToken.TokenType == token;
        }
        public bool ExpectPeek(TokenEnum token)
        {
            if (PeekTokenIs(token))
            {
                NextToken();
                return true;
            }
            else
            {
                return false;
            }
        }
        public Dictionary<TokenEnum, Func<Expression>> Prefix { get; set; } = new Dictionary<TokenEnum, Func<Expression>>();
        public Dictionary<TokenEnum, Func<Expression, Expression>> Infix { get; set; } = new Dictionary<TokenEnum, Func<Expression, Expression>>();
    }
    internal class Program
    {

        static void Main(string[] args)
        {
            var item = "1 + 2 * 3 / (4 - 1)+-1";
            var lexer = Lexer.Create(item);
            var parser = Parser.Instance.Start(lexer);
        }

    }
}
